//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_entry_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/api_coll_dao"
	"atomgit.com/openlinksaas/api-server/dao/comment_dao"
	"atomgit.com/openlinksaas/api-server/dao/data_anno_dao"
	"atomgit.com/openlinksaas/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_doc_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/dao/watch_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_entry"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_comment_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_entry_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_recycle_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_watch_api"
	"go.mongodb.org/mongo-driver/mongo"
)

type ProjectEntryApiImpl struct {
	project_entry_api.UnimplementedProjectEntryApiServer
}

func (apiImpl *ProjectEntryApiImpl) Create(ctx context.Context, req *project_entry_api.CreateRequest) (*project_entry_api.CreateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.CreateResponse{
			Code:   project_entry_api.CreateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.CreateResponse{
			Code:   project_entry_api.CreateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.CreateResponse{
			Code:   project_entry_api.CreateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查目录是否存在
	if req.ParentFolderId != "" {
		exist, err := project_entry_dao.FolderDao.Exist(ctx, req.ProjectId, req.ParentFolderId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_entry_api.CreateResponse{
				Code:   project_entry_api.CreateResponse_CODE_NO_PARENT_FOLDER,
				ErrMsg: "父目录不存在",
			}, nil
		}
	}
	//检查是否存在入口
	exist, err := project_entry_dao.EntryDao.Exist(ctx, req.EntryId, req.ProjectId)
	if err != nil {
		return nil, err
	}
	if exist {
		return &project_entry_api.CreateResponse{
			Code:   project_entry_api.CreateResponse_CODE_EXIST_ENTRY,
			ErrMsg: "入口记录已存在",
		}, nil
	}
	//检查类型
	if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DOC {
		exist, err = project_doc_dao.DocContentDao.Exist(ctx, req.EntryId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_entry_api.CreateResponse{
				Code:   project_entry_api.CreateResponse_CODE_NO_CONTENT,
				ErrMsg: "对应内容不存在",
			}, nil
		}
	} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT {
		exist, err := issue_dao.SpritDao.Exist(ctx, req.ProjectId, req.EntryId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_entry_api.CreateResponse{
				Code:   project_entry_api.CreateResponse_CODE_NO_CONTENT,
				ErrMsg: "对应内容不存在",
			}, nil
		}
	} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_PAGES || req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_BOARD ||
		req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_FILE {
		//do nothing
	} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL {
		extraInfo := req.ExtraInfo.(*project_entry_api.CreateRequest_ExtraApiCollInfo)
		if extraInfo.ExtraApiCollInfo.ApiCollType == project_entry_api.API_COLL_TYPE_API_COLL_GRPC {
			exist, err = api_coll_dao.GrpcExtraDao.Exist(ctx, req.EntryId)
			if err != nil {
				return nil, err
			}
			if !exist {
				return &project_entry_api.CreateResponse{
					Code:   project_entry_api.CreateResponse_CODE_NO_CONTENT,
					ErrMsg: "对应内容不存在",
				}, nil
			}
		} else if extraInfo.ExtraApiCollInfo.ApiCollType == project_entry_api.API_COLL_TYPE_API_COLL_OPENAPI {
			exist, err = api_coll_dao.OpenApiExtraDao.Exist(ctx, req.EntryId)
			if err != nil {
				return nil, err
			}
			if !exist {
				return &project_entry_api.CreateResponse{
					Code:   project_entry_api.CreateResponse_CODE_NO_CONTENT,
					ErrMsg: "对应内容不存在",
				}, nil
			}
		} else if extraInfo.ExtraApiCollInfo.ApiCollType == project_entry_api.API_COLL_TYPE_API_COLL_CUSTOM {
			exist, err = api_coll_dao.CustomExtraDao.Exist(ctx, req.EntryId)
			if err != nil {
				return nil, err
			}
			if !exist {
				return &project_entry_api.CreateResponse{
					Code:   project_entry_api.CreateResponse_CODE_NO_CONTENT,
					ErrMsg: "对应内容不存在",
				}, nil
			}
		}
	} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DATA_ANNO {
		exist, err = data_anno_dao.AnnoProjectDao.Exist(ctx, req.ProjectId, req.EntryId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_entry_api.CreateResponse{
				Code:   project_entry_api.CreateResponse_CODE_NO_CONTENT,
				ErrMsg: "对应内容不存在",
			}, nil
		}
	} else {
		return &project_entry_api.CreateResponse{
			Code:   project_entry_api.CreateResponse_CODE_NO_CONTENT,
			ErrMsg: "对应内容不存在",
		}, nil
	}

	//检查标签
	tagItemList, err := project_dao.TagInfoDao.List(ctx, req.ProjectId, project_api.TAG_SCOPE_TYPE_TAG_SCOPE_ENTRY)
	if err != nil {
		return nil, err
	}
	tagIdMap := map[string]bool{}
	for _, tagItem := range tagItemList {
		tagIdMap[tagItem.TagId] = true
	}
	for _, tagId := range req.TagIdList {
		_, ok := tagIdMap[tagId]
		if !ok {
			return &project_entry_api.CreateResponse{
				Code:   project_entry_api.CreateResponse_CODE_NO_TAG,
				ErrMsg: "部分标签不存在",
			}, nil
		}
	}
	//检查权限成员
	if len(req.EntryPerm.ExtraUpdateUserIdList) > 0 {
		memberUserIdList, err := project_dao.MemberInfoDao.ListMemberId(ctx, req.ProjectId)
		if err != nil {
			return nil, err
		}
		memberUserIdMap := map[string]bool{}
		for _, memberUserId := range memberUserIdList {
			memberUserIdMap[memberUserId] = true
		}
		for _, userId := range req.EntryPerm.ExtraUpdateUserIdList {
			_, ok := memberUserIdMap[userId]
			if !ok {
				return &project_entry_api.CreateResponse{
					Code:   project_entry_api.CreateResponse_CODE_NO_TARGET_MEMBER,
					ErrMsg: "项目成员不存在",
				}, nil
			}
		}
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		entryItem := &project_entry_dao.EntryInfoDbItem{
			EntryId:        req.EntryId,
			ProjectId:      req.ProjectId,
			ParentFolderId: req.ParentFolderId,
			EntryType:      uint32(req.EntryType),
			EntryTitle:     req.EntryTitle,
			MarkSys:        false,
			TagIdList:      req.TagIdList,
			EntryPerm: project_entry_dao.EntryPermDbItem{
				UpdateForAll:          req.EntryPerm.UpdateForAll,
				ExtraUpdateUserIdList: req.EntryPerm.ExtraUpdateUserIdList,
			},
			CreateUserId: sessionItem.UserId,
			CreateTime:   nowTime,
			UpdateUserId: sessionItem.UserId,
			UpdateTime:   nowTime,
		}
		if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT {
			extraInfo := req.ExtraInfo.(*project_entry_api.CreateRequest_ExtraSpritInfo)
			entryItem.ExtraSpritInfo = &project_entry_dao.ExtraSpritInfoDbItem{
				StartTime:         extraInfo.ExtraSpritInfo.StartTime,
				EndTime:           extraInfo.ExtraSpritInfo.EndTime,
				NonWorkDayList:    extraInfo.ExtraSpritInfo.NonWorkDayList,
				IssueListType:     uint32(extraInfo.ExtraSpritInfo.IssueListType),
				HideGanttPanel:    extraInfo.ExtraSpritInfo.HideGanttPanel,
				HideBurndownPanel: extraInfo.ExtraSpritInfo.HideBurndownPanel,
				HideStatPanel:     extraInfo.ExtraSpritInfo.HideStatPanel,
				HideSummaryPanel:  extraInfo.ExtraSpritInfo.HideSummaryPanel,
				HideTestPlanPanel: extraInfo.ExtraSpritInfo.HideTestPlanPanel,
			}
		} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_PAGES {
			extraInfo := req.ExtraInfo.(*project_entry_api.CreateRequest_ExtraPagesInfo)
			entryItem.ExtraPagesInfo = &project_entry_dao.ExtraPagesInfoDbItem{
				FileId: extraInfo.ExtraPagesInfo.FileId,
			}
		} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_FILE {
			extraInfo := req.ExtraInfo.(*project_entry_api.CreateRequest_ExtraFileInfo)
			entryItem.ExtraFileInfo = &project_entry_dao.ExtraFileInfoDbItem{
				FileId:   extraInfo.ExtraFileInfo.FileId,
				FileName: extraInfo.ExtraFileInfo.FileName,
			}
		} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL {
			extraInfo := req.ExtraInfo.(*project_entry_api.CreateRequest_ExtraApiCollInfo)
			entryItem.ExtraApiCollInfo = &project_entry_dao.ExtraApiCollInfoDbItem{
				ApiCollType: uint32(extraInfo.ExtraApiCollInfo.ApiCollType),
				DefaultAddr: extraInfo.ExtraApiCollInfo.DefaultAddr,
			}
		} else if req.EntryType == project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DATA_ANNO {
			extraInfo := req.ExtraInfo.(*project_entry_api.CreateRequest_ExtraDataAnnoInfo)
			entryItem.ExtraDataAnnoInfo = &project_entry_dao.ExtraDataAnnoInfoDbItem{
				AnnoType: uint32(extraInfo.ExtraDataAnnoInfo.AnnoType),
			}
		}
		err = project_entry_dao.EntryDao.Insert(sessCtx, entryItem)
		if err != nil {
			return nil, err
		}
		//更新父目录状态
		if req.ParentFolderId != "" {
			count, err := project_entry_dao.EntryDao.CountByParentFolder(sessCtx, req.ProjectId, req.ParentFolderId)
			if err != nil {
				return nil, err
			}
			err = project_entry_dao.FolderDao.UpdateSubEntryCount(sessCtx, req.ProjectId, req.ParentFolderId, count)
			if err != nil {
				return nil, err
			}
		}
		return &project_entry_api.CreateResponse{
			Code: project_entry_api.CreateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addCreateEvent(sessionItem, req, projectItem, nowTime)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_entry.NewEntryNotice{
		ProjectId:    req.ProjectId,
		EntryId:      req.EntryId,
		CreateUserId: sessionItem.UserId,
	})
	return ret.(*project_entry_api.CreateResponse), nil
}

func (apiImpl *ProjectEntryApiImpl) List(ctx context.Context, req *project_entry_api.ListRequest) (*project_entry_api.ListResponse, error) {
	emptyList := []*project_entry_api.EntryInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.ListResponse{
			Code:      project_entry_api.ListResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			EntryList: emptyList,
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.ListResponse{
			Code:      project_entry_api.ListResponse_CODE_NO_PROJECT,
			ErrMsg:    "项目不存在",
			EntryList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.ListResponse{
			Code:      project_entry_api.ListResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			EntryList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	watchEntryIdList := []string{}
	if req.ListParam.FilterByWatch {
		watchEntryIdList, err = watch_dao.MyWatchDao.DistinctTargetId(ctx, req.ProjectId, sessionItem.UserId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_ENTRY))
		if err != nil {
			return nil, err
		}
	}

	count, err := project_entry_dao.EntryDao.Count(ctx, req.ProjectId, req.ListParam, watchEntryIdList)
	if err != nil {
		return nil, err
	}
	entryItemList, err := project_entry_dao.EntryDao.List(ctx, req.ProjectId, req.ListParam, watchEntryIdList, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}

	//获取标签信息
	tagItemList, err := project_dao.TagInfoDao.List(ctx, req.ProjectId, project_api.TAG_SCOPE_TYPE_TAG_SCOPE_ENTRY)
	if err != nil {
		return nil, err
	}
	tagItemMap := map[string]*project_dao.TagInfoDbItem{}
	for _, tagItem := range tagItemList {
		tagItemMap[tagItem.TagId] = tagItem
	}
	//获取关注信息
	entryIdList := []string{}
	for _, entryItem := range entryItemList {
		entryIdList = append(entryIdList, entryItem.EntryId)
	}
	watchItemMap, watchUserIdList, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_ENTRY), entryIdList)
	if err != nil {
		return nil, err
	}

	//补充用户信息
	userIdList := []string{}
	for _, entryItem := range entryItemList {
		userIdList = append(userIdList, entryItem.CreateUserId)
		userIdList = append(userIdList, entryItem.UpdateUserId)
	}
	userIdList = append(userIdList, watchUserIdList...)
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	entryList := []*project_entry_api.EntryInfo{}
	for _, entryItem := range entryItemList {
		tagList := []*project_entry_api.EntryTag{}
		for _, tagId := range entryItem.TagIdList {
			tagItem, ok := tagItemMap[tagId]
			if ok {
				tagList = append(tagList, &project_entry_api.EntryTag{
					TagId:   tagItem.TagId,
					TagName: tagItem.TagName,
					BgColor: tagItem.BgColor,
				})
			}
		}
		entry := entryItem.ToEntryInfo(tagList)
		createUser, ok := userItemMap[entryItem.CreateUserId]
		if ok {
			entry.CreateDisplayName = createUser.BasicInfo.DisplayName
			entry.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[entryItem.UpdateUserId]
		if ok {
			entry.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			entry.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		entry.CanUpdate = api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
		entry.CanRemove = api_common.CheckEntryCanRemove(sessionItem, projectItem, roleItem, entryItem)
		watchUserIdList, ok := watchItemMap[entryItem.EntryId]
		if ok {
			for _, watchUserId := range watchUserIdList {
				if watchUserId == sessionItem.UserId {
					entry.MyWatch = true
				}
				userItem, ok := userItemMap[watchUserId]
				if ok {
					entry.WatchUserList = append(entry.WatchUserList, &project_entry_api.WatchUser{
						MemberUserId: userItem.UserId,
						DisplayName:  userItem.BasicInfo.DisplayName,
						LogoUri:      userItem.BasicInfo.LogoUri,
					})
				}
			}
		}
		entryList = append(entryList, entry)
	}

	return &project_entry_api.ListResponse{
		Code:       project_entry_api.ListResponse_CODE_OK,
		TotalCount: count,
		EntryList:  entryList,
	}, nil
}

func (apiImpl *ProjectEntryApiImpl) ListSys(ctx context.Context, req *project_entry_api.ListSysRequest) (*project_entry_api.ListSysResponse, error) {
	emptyList := []*project_entry_api.EntryInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.ListSysResponse{
			Code:      project_entry_api.ListSysResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			EntryList: emptyList,
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.ListSysResponse{
			Code:      project_entry_api.ListSysResponse_CODE_NO_PROJECT,
			ErrMsg:    "项目不存在",
			EntryList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.ListSysResponse{
			Code:      project_entry_api.ListSysResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			EntryList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	entryItemList, err := project_entry_dao.EntryDao.ListSys(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}

	//获取标签信息
	tagItemList, err := project_dao.TagInfoDao.List(ctx, req.ProjectId, project_api.TAG_SCOPE_TYPE_TAG_SCOPE_ENTRY)
	if err != nil {
		return nil, err
	}
	tagItemMap := map[string]*project_dao.TagInfoDbItem{}
	for _, tagItem := range tagItemList {
		tagItemMap[tagItem.TagId] = tagItem
	}

	//获取关注信息
	entryIdList := []string{}
	for _, entryItem := range entryItemList {
		entryIdList = append(entryIdList, entryItem.EntryId)
	}
	watchItemMap, watchUserIdList, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_ENTRY), entryIdList)
	if err != nil {
		return nil, err
	}

	//补充用户信息
	userIdList := []string{}
	for _, entryItem := range entryItemList {
		userIdList = append(userIdList, entryItem.CreateUserId)
		userIdList = append(userIdList, entryItem.UpdateUserId)
	}
	userIdList = append(userIdList, watchUserIdList...)
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	entryList := []*project_entry_api.EntryInfo{}
	for _, entryItem := range entryItemList {
		tagList := []*project_entry_api.EntryTag{}
		for _, tagId := range entryItem.TagIdList {
			tagItem, ok := tagItemMap[tagId]
			if ok {
				tagList = append(tagList, &project_entry_api.EntryTag{
					TagId:   tagItem.TagId,
					TagName: tagItem.TagName,
					BgColor: tagItem.BgColor,
				})
			}
		}
		entry := entryItem.ToEntryInfo(tagList)
		createUser, ok := userItemMap[entryItem.CreateUserId]
		if ok {
			entry.CreateDisplayName = createUser.BasicInfo.DisplayName
			entry.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[entryItem.UpdateUserId]
		if ok {
			entry.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			entry.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		entry.CanUpdate = api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
		entry.CanRemove = api_common.CheckEntryCanRemove(sessionItem, projectItem, roleItem, entryItem)
		watchUserIdList, ok := watchItemMap[entryItem.EntryId]
		if ok {
			for _, watchUserId := range watchUserIdList {
				if watchUserId == sessionItem.UserId {
					entry.MyWatch = true
				}
				userItem, ok := userItemMap[watchUserId]
				if ok {
					entry.WatchUserList = append(entry.WatchUserList, &project_entry_api.WatchUser{
						MemberUserId: userItem.UserId,
						DisplayName:  userItem.BasicInfo.DisplayName,
						LogoUri:      userItem.BasicInfo.LogoUri,
					})
				}
			}
		}
		entryList = append(entryList, entry)
	}

	return &project_entry_api.ListSysResponse{
		Code:      project_entry_api.ListSysResponse_CODE_OK,
		EntryList: entryList,
	}, nil
}

func (apiImpl *ProjectEntryApiImpl) Get(ctx context.Context, req *project_entry_api.GetRequest) (*project_entry_api.GetResponse, error) {
	emptyEntry := &project_entry_api.EntryInfo{
		TagList:       []*project_entry_api.EntryTag{},
		WatchUserList: []*project_entry_api.WatchUser{},
		EntryPerm: &project_entry_api.EntryPerm{
			ExtraUpdateUserIdList: []string{},
		},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.GetResponse{
			Code:   project_entry_api.GetResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Entry:  emptyEntry,
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.GetResponse{
			Code:   project_entry_api.GetResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			Entry:  emptyEntry,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.GetResponse{
			Code:   project_entry_api.GetResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Entry:  emptyEntry,
		}, nil
	} else if err != nil {
		return nil, err
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.EntryId, req.ProjectId)
	if err != nil {
		return &project_entry_api.GetResponse{
			Code:   project_entry_api.GetResponse_CODE_NO_ENTRY,
			ErrMsg: "内容入口不存在",
			Entry:  emptyEntry,
		}, nil
	}

	//获取标签信息
	tagItemList, err := project_dao.TagInfoDao.List(ctx, req.ProjectId, project_api.TAG_SCOPE_TYPE_TAG_SCOPE_ENTRY)
	if err != nil {
		return nil, err
	}
	tagItemMap := map[string]*project_dao.TagInfoDbItem{}
	for _, tagItem := range tagItemList {
		tagItemMap[tagItem.TagId] = tagItem
	}

	//获取关注信息
	watchItemMap, watchUserIdList, err := watch_dao.MyWatchDao.CalcWatchUserMap(ctx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_ENTRY), []string{req.EntryId})
	if err != nil {
		return nil, err
	}

	//补充用户信息
	userIdList := []string{entryItem.CreateUserId, entryItem.UpdateUserId}
	userIdList = append(userIdList, watchUserIdList...)
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	tagList := []*project_entry_api.EntryTag{}
	for _, tagId := range entryItem.TagIdList {
		tagItem, ok := tagItemMap[tagId]
		if ok {
			tagList = append(tagList, &project_entry_api.EntryTag{
				TagId:   tagItem.TagId,
				TagName: tagItem.TagName,
				BgColor: tagItem.BgColor,
			})
		}
	}

	//生成结果
	entry := entryItem.ToEntryInfo(tagList)
	createUser, ok := userItemMap[entryItem.CreateUserId]
	if ok {
		entry.CreateDisplayName = createUser.BasicInfo.DisplayName
		entry.CreateLogoUri = createUser.BasicInfo.LogoUri
	}
	updateUser, ok := userItemMap[entryItem.UpdateUserId]
	if ok {
		entry.UpdateDisplayName = updateUser.BasicInfo.DisplayName
		entry.UpdateLogoUri = updateUser.BasicInfo.LogoUri
	}
	entry.CanUpdate = api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
	entry.CanRemove = api_common.CheckEntryCanRemove(sessionItem, projectItem, roleItem, entryItem)
	watchUserIdList, ok = watchItemMap[entryItem.EntryId]
	if ok {
		for _, watchUserId := range watchUserIdList {
			if watchUserId == sessionItem.UserId {
				entry.MyWatch = true
			}
			userItem, ok := userItemMap[watchUserId]
			if ok {
				entry.WatchUserList = append(entry.WatchUserList, &project_entry_api.WatchUser{
					MemberUserId: userItem.UserId,
					DisplayName:  userItem.BasicInfo.DisplayName,
					LogoUri:      userItem.BasicInfo.LogoUri,
				})
			}
		}
	}

	return &project_entry_api.GetResponse{
		Code:  project_entry_api.GetResponse_CODE_OK,
		Entry: entry,
	}, nil
}

func (apiImpl *ProjectEntryApiImpl) Remove(ctx context.Context, req *project_entry_api.RemoveRequest) (*project_entry_api.RemoveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.RemoveResponse{
			Code:   project_entry_api.RemoveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.RemoveResponse{
			Code:   project_entry_api.RemoveResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.RemoveResponse{
			Code:   project_entry_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.EntryId, req.ProjectId)
	if err != nil { //记录不存在
		return &project_entry_api.RemoveResponse{
			Code: project_entry_api.RemoveResponse_CODE_OK,
		}, nil
	}

	canRemove := api_common.CheckEntryCanRemove(sessionItem, projectItem, roleItem, entryItem)
	if !canRemove {
		return &project_entry_api.RemoveResponse{
			Code:   project_entry_api.RemoveResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	recycleItemType := project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_SPRIT
	if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
		recycleItemType = project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_SPRIT
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DOC) {
		recycleItemType = project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_DOC
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_PAGES) {
		recycleItemType = project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_PAGES
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_BOARD) {
		recycleItemType = project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_BOARD
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_FILE) {
		recycleItemType = project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_FILE
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL) {
		recycleItemType = project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_API_COLL
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DATA_ANNO) {
		recycleItemType = project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_DATA_ANNO
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//删除内容入口
		err = project_entry_dao.EntryDao.Remove(sessCtx, req.EntryId, req.ProjectId)
		if err != nil {
			return nil, err
		}
		err = project_entry_dao.EntryRecycleDao.Insert(sessCtx, entryItem)
		if err != nil {
			return nil, err
		}

		err = project_dao.RecycleDao.Insert(sessCtx, &project_dao.RecycleItemInfoDbItem{
			RecycleItemId:   req.EntryId,
			ProjectId:       req.ProjectId,
			RecycleItemType: uint32(recycleItemType),
			RemoveUserId:    sessionItem.UserId,
			RemoveTime:      nowTime,
		})
		if err != nil {
			return nil, err
		}

		//处理父目录状态
		if entryItem.ParentFolderId != "" {
			count, err := project_entry_dao.EntryDao.CountByParentFolder(sessCtx, req.ProjectId, entryItem.ParentFolderId)
			if err != nil {
				return nil, err
			}
			err = project_entry_dao.FolderDao.UpdateSubEntryCount(sessCtx, req.ProjectId, entryItem.ParentFolderId, count)
			if err != nil {
				return nil, err
			}
		}
		//删除关注
		err = watch_dao.MyWatchDao.RemoveByTarget(sessCtx, req.ProjectId, uint32(project_watch_api.WATCH_TARGET_TYPE_WATCH_TARGET_ENTRY), req.EntryId)
		if err != nil {
			return nil, err
		}
		//删除未读评论通知
		err = comment_dao.UnReadDao.RemoveByTarget(sessCtx, req.ProjectId, uint32(project_comment_api.COMMENT_TARGET_TYPE_COMMENT_TARGET_ENTRY), req.EntryId)
		if err != nil {
			return nil, err
		}
		return &project_entry_api.RemoveResponse{
			Code: project_entry_api.RemoveResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go api_common.AddRemoveEntryEvent(sessionItem, projectItem, entryItem, nowTime)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_entry.RemoveEntryNotice{
		ProjectId: req.ProjectId,
		EntryId:   req.EntryId,
	})
	return ret.(*project_entry_api.RemoveResponse), nil
}

func (apiImpl *ProjectEntryApiImpl) UpdateTag(ctx context.Context, req *project_entry_api.UpdateTagRequest) (*project_entry_api.UpdateTagResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.UpdateTagResponse{
			Code:   project_entry_api.UpdateTagResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.UpdateTagResponse{
			Code:   project_entry_api.UpdateTagResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.UpdateTagResponse{
			Code:   project_entry_api.UpdateTagResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查内容入口是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.EntryId, req.ProjectId)
	if err != nil {
		return &project_entry_api.UpdateTagResponse{
			Code:   project_entry_api.UpdateTagResponse_CODE_NO_ENTRY,
			ErrMsg: "内容入口不存在",
		}, nil
	}
	canUpdate := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
	if !canUpdate {
		return &project_entry_api.UpdateTagResponse{
			Code:   project_entry_api.UpdateTagResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查标签是否存在
	tagItemList, err := project_dao.TagInfoDao.List(ctx, req.ProjectId, project_api.TAG_SCOPE_TYPE_TAG_SCOPE_ENTRY)
	if err != nil {
		return nil, err
	}
	tagIdMap := map[string]bool{}
	for _, tagItem := range tagItemList {
		tagIdMap[tagItem.TagId] = true
	}
	for _, tagId := range req.TagIdList {
		_, ok := tagIdMap[tagId]
		if !ok {
			return &project_entry_api.UpdateTagResponse{
				Code:   project_entry_api.UpdateTagResponse_CODE_NO_TAG,
				ErrMsg: "部分标签不存在",
			}, nil
		}
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_entry_dao.EntryDao.UpdateTag(sessCtx, req.EntryId, req.ProjectId, req.TagIdList, sessionItem.UserId, time.Now().UnixNano()/1e6)
		if err != nil {
			return nil, err
		}
		return &project_entry_api.UpdateTagResponse{
			Code: project_entry_api.UpdateTagResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_entry.UpdateEntryNotice{
		ProjectId: req.ProjectId,
		EntryId:   req.EntryId,
	})
	return ret.(*project_entry_api.UpdateTagResponse), nil
}

func (apiImpl *ProjectEntryApiImpl) UpdateTitle(ctx context.Context, req *project_entry_api.UpdateTitleRequest) (*project_entry_api.UpdateTitleResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.UpdateTitleResponse{
			Code:   project_entry_api.UpdateTitleResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.UpdateTitleResponse{
			Code:   project_entry_api.UpdateTitleResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.UpdateTitleResponse{
			Code:   project_entry_api.UpdateTitleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查内容入口是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.EntryId, req.ProjectId)
	if err != nil {
		return &project_entry_api.UpdateTitleResponse{
			Code:   project_entry_api.UpdateTitleResponse_CODE_NO_ENTRY,
			ErrMsg: "内容入口不存在",
		}, nil
	}
	canUpdate := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
	if !canUpdate {
		return &project_entry_api.UpdateTitleResponse{
			Code:   project_entry_api.UpdateTitleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_entry_dao.EntryDao.UpdateTitle(sessCtx, req.EntryId, req.ProjectId, req.Title, sessionItem.UserId, time.Now().UnixNano()/1e6)
		if err != nil {
			return nil, err
		}
		return &project_entry_api.UpdateTitleResponse{
			Code: project_entry_api.UpdateTitleResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_entry.UpdateEntryNotice{
		ProjectId: req.ProjectId,
		EntryId:   req.EntryId,
	})
	return ret.(*project_entry_api.UpdateTitleResponse), nil
}

func (apiImpl *ProjectEntryApiImpl) UpdatePerm(ctx context.Context, req *project_entry_api.UpdatePermRequest) (*project_entry_api.UpdatePermResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.UpdatePermResponse{
			Code:   project_entry_api.UpdatePermResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.UpdatePermResponse{
			Code:   project_entry_api.UpdatePermResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.UpdatePermResponse{
			Code:   project_entry_api.UpdatePermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查内容入口是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.EntryId, req.ProjectId)
	if err != nil {
		return &project_entry_api.UpdatePermResponse{
			Code:   project_entry_api.UpdatePermResponse_CODE_NO_ENTRY,
			ErrMsg: "内容入口不存在",
		}, nil
	}
	canUpdate := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
	if !canUpdate {
		return &project_entry_api.UpdatePermResponse{
			Code:   project_entry_api.UpdatePermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查目标成员是否属于项目
	if len(req.EntryPerm.ExtraUpdateUserIdList) > 0 {
		memberUserIdList, err := project_dao.MemberInfoDao.ListMemberId(ctx, req.ProjectId)
		if err != nil {
			return nil, err
		}
		memberUserIdMap := map[string]bool{}
		for _, memberUserId := range memberUserIdList {
			memberUserIdMap[memberUserId] = true
		}
		for _, userId := range req.EntryPerm.ExtraUpdateUserIdList {
			_, ok := memberUserIdMap[userId]
			if !ok {
				return &project_entry_api.UpdatePermResponse{
					Code:   project_entry_api.UpdatePermResponse_CODE_NO_TARGET_MEMBER,
					ErrMsg: "项目成员不存在",
				}, nil
			}
		}
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_entry_dao.EntryDao.UpdatePerm(sessCtx, req.EntryId, req.ProjectId, &project_entry_dao.EntryPermDbItem{
			UpdateForAll:          req.EntryPerm.UpdateForAll,
			ExtraUpdateUserIdList: req.EntryPerm.ExtraUpdateUserIdList,
		}, sessionItem.UserId, time.Now().UnixNano()/1e6)
		if err != nil {
			return nil, err
		}
		return &project_entry_api.UpdatePermResponse{
			Code: project_entry_api.UpdatePermResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_entry.UpdateEntryNotice{
		ProjectId: req.ProjectId,
		EntryId:   req.EntryId,
	})
	return ret.(*project_entry_api.UpdatePermResponse), nil
}

func (apiImpl *ProjectEntryApiImpl) UpdateMarkSys(ctx context.Context, req *project_entry_api.UpdateMarkSysRequest) (*project_entry_api.UpdateMarkSysResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.UpdateMarkSysResponse{
			Code:   project_entry_api.UpdateMarkSysResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.UpdateMarkSysResponse{
			Code:   project_entry_api.UpdateMarkSysResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.UpdateMarkSysResponse{
			Code:   project_entry_api.UpdateMarkSysResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查内容入口是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.EntryId, req.ProjectId)
	if err != nil {
		return &project_entry_api.UpdateMarkSysResponse{
			Code:   project_entry_api.UpdateMarkSysResponse_CODE_NO_ENTRY,
			ErrMsg: "内容入口不存在",
		}, nil
	}
	canUpdate := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
	if !canUpdate {
		return &project_entry_api.UpdateMarkSysResponse{
			Code:   project_entry_api.UpdateMarkSysResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_entry_dao.EntryDao.UpdateMarkSys(sessCtx, req.EntryId, req.ProjectId, req.MarkSys)
		if err != nil {
			return nil, err
		}
		return &project_entry_api.UpdateMarkSysResponse{
			Code: project_entry_api.UpdateMarkSysResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_entry.UpdateEntryNotice{
		ProjectId: req.ProjectId,
		EntryId:   req.EntryId,
	})
	return ret.(*project_entry_api.UpdateMarkSysResponse), nil
}

func (apiImpl *ProjectEntryApiImpl) UpdateExtraInfo(ctx context.Context, req *project_entry_api.UpdateExtraInfoRequest) (*project_entry_api.UpdateExtraInfoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_entry_api.UpdateExtraInfoResponse{
			Code:   project_entry_api.UpdateExtraInfoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_entry_api.UpdateExtraInfoResponse{
			Code:   project_entry_api.UpdateExtraInfoResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_entry_api.UpdateExtraInfoResponse{
			Code:   project_entry_api.UpdateExtraInfoResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查内容入口是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.EntryId, req.ProjectId)
	if err != nil {
		return &project_entry_api.UpdateExtraInfoResponse{
			Code:   project_entry_api.UpdateExtraInfoResponse_CODE_NO_ENTRY,
			ErrMsg: "内容入口不存在",
		}, nil
	}
	canUpdate := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)
	if !canUpdate {
		return &project_entry_api.UpdateExtraInfoResponse{
			Code:   project_entry_api.UpdateExtraInfoResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
		_, ok := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraSpritInfo)
		if !ok {
			return &project_entry_api.UpdateExtraInfoResponse{
				Code:   project_entry_api.UpdateExtraInfoResponse_CODE_WRONG_TYPE,
				ErrMsg: "错误的内容入口类型",
			}, nil
		}
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_PAGES) {
		_, ok := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraPagesInfo)
		if !ok {
			return &project_entry_api.UpdateExtraInfoResponse{
				Code:   project_entry_api.UpdateExtraInfoResponse_CODE_WRONG_TYPE,
				ErrMsg: "错误的内容入口类型",
			}, nil
		}
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_FILE) {
		_, ok := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraFileInfo)
		if !ok {
			return &project_entry_api.UpdateExtraInfoResponse{
				Code:   project_entry_api.UpdateExtraInfoResponse_CODE_WRONG_TYPE,
				ErrMsg: "错误的内容入口类型",
			}, nil
		}
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL) {
		newExtraInfo, ok := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraApiCollInfo)
		if !ok {
			return &project_entry_api.UpdateExtraInfoResponse{
				Code:   project_entry_api.UpdateExtraInfoResponse_CODE_WRONG_TYPE,
				ErrMsg: "错误的内容入口类型",
			}, nil
		}
		if newExtraInfo.ExtraApiCollInfo.ApiCollType != project_entry_api.API_COLL_TYPE(entryItem.ExtraApiCollInfo.ApiCollType) {
			return &project_entry_api.UpdateExtraInfoResponse{
				Code:   project_entry_api.UpdateExtraInfoResponse_CODE_NO_PERMISSION,
				ErrMsg: "无法变更API类型",
			}, nil
		}
	} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DATA_ANNO) {
		return &project_entry_api.UpdateExtraInfoResponse{
			Code:   project_entry_api.UpdateExtraInfoResponse_CODE_NO_PERMISSION,
			ErrMsg: "无法变更标注类型",
		}, nil
	} else {
		return &project_entry_api.UpdateExtraInfoResponse{
			Code:   project_entry_api.UpdateExtraInfoResponse_CODE_WRONG_TYPE,
			ErrMsg: "错误的内容入口类型",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
			extraInfo := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraSpritInfo)
			err = project_entry_dao.EntryDao.UpdateExtraSpritInfo(sessCtx, req.EntryId, req.ProjectId, &project_entry_dao.ExtraSpritInfoDbItem{
				StartTime:         extraInfo.ExtraSpritInfo.StartTime,
				EndTime:           extraInfo.ExtraSpritInfo.EndTime,
				NonWorkDayList:    extraInfo.ExtraSpritInfo.NonWorkDayList,
				IssueListType:     uint32(extraInfo.ExtraSpritInfo.IssueListType),
				HideGanttPanel:    extraInfo.ExtraSpritInfo.HideGanttPanel,
				HideBurndownPanel: extraInfo.ExtraSpritInfo.HideBurndownPanel,
				HideStatPanel:     extraInfo.ExtraSpritInfo.HideStatPanel,
				HideSummaryPanel:  extraInfo.ExtraSpritInfo.HideSummaryPanel,
				HideTestPlanPanel: extraInfo.ExtraSpritInfo.HideTestPlanPanel,
			}, sessionItem.UserId, nowTime)
			if err != nil {
				return nil, err
			}
		} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_PAGES) {
			extraInfo := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraPagesInfo)
			err = project_entry_dao.EntryDao.UpdateExtraPagesInfo(sessCtx, req.EntryId, req.ProjectId, &project_entry_dao.ExtraPagesInfoDbItem{
				FileId: extraInfo.ExtraPagesInfo.FileId,
			}, sessionItem.UserId, nowTime)
			if err != nil {
				return nil, err
			}
		} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_FILE) {
			extraInfo := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraFileInfo)
			err = project_entry_dao.EntryDao.UpdateExtraFileInfo(sessCtx, req.EntryId, req.ProjectId, &project_entry_dao.ExtraFileInfoDbItem{
				FileId:   extraInfo.ExtraFileInfo.FileId,
				FileName: extraInfo.ExtraFileInfo.FileName,
			}, sessionItem.UserId, nowTime)
			if err != nil {
				return nil, err
			}
		} else if entryItem.EntryType == uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL) {
			extraInfo := req.ExtraInfo.(*project_entry_api.UpdateExtraInfoRequest_ExtraApiCollInfo)
			err = project_entry_dao.EntryDao.UpdateExtraApiCollInfo(sessCtx, req.EntryId, req.ProjectId, &project_entry_dao.ExtraApiCollInfoDbItem{
				ApiCollType: uint32(extraInfo.ExtraApiCollInfo.ApiCollType),
				DefaultAddr: extraInfo.ExtraApiCollInfo.DefaultAddr,
			}, sessionItem.UserId, nowTime)
			if err != nil {
				return nil, err
			}
		}
		return &project_entry_api.UpdateExtraInfoResponse{
			Code: project_entry_api.UpdateExtraInfoResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_entry.UpdateEntryNotice{
		ProjectId: req.ProjectId,
		EntryId:   req.EntryId,
	})
	return ret.(*project_entry_api.UpdateExtraInfoResponse), nil
}
